﻿using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Util;
namespace UtilEditors
{

    public class SubsidiaryWindow : BaseEditorWindow
    {
        public List<Inspector> Alllist = new List<Inspector>();

        [MenuItem("Tools/辅助/BaseWindow")]
        public static void Init()
        {
            Init<SubsidiaryWindow>();
        }

        public override void OnEnable()
        {
            Inits();
            mtimers = 100;
        }

        private void Inits()
        {
            InspectorStart();
            for (int k = 0; k < Alllist.Count; k++)
            {
                Alllist[k].Init(this, k);
            }
            OnSelectionChange();
            Vector2 pos = new Vector2(0, 260);
            for (int k = 0; k < Alllist.Count; k++)
            {
                if (Alllist[k].IsShow)
                {
                    Alllist[k].rect.x = pos.x;
                    Alllist[k].rect.y = pos.y;
                    pos.x += Alllist[k].rect.width + 10;
                }
            }
        }
        public void AddInspector(Inspector inspector)
        {
            Alllist.Add(inspector);
            inspector.Init(this, Alllist.Count);
            OnSelectionChange();
        }
        void InspectorStart()
        {
            Alllist.Clear();
            Alllist.Add(new TransformEditers());
            Alllist.Add(new RigidbodyEditers());
            Alllist.Add(new Rigidbody2DEditers());
            Alllist.Add(new SpriteRendererEditers());
            Alllist.Add(new PolygonCollder2dEditers());

            //继承了 <T> 的父类层级当作不存在了
            //var types = Assembly.GetCallingAssembly().GetTypes();
            //var aType = typeof(Inspector);
            //foreach (var type in types)
            //{
            //    var baseType = type.BaseType;  //获取基类
            //    while (baseType != null)  //获取所有基类
            //    {
            //        if (baseType.Name == aType.Name)
            //        {
            //            debug.log(baseType.Name, aType.Name);
            //            Type objtype = Type.GetType(type.FullName, true);
            //            object obj = Activator.CreateInstance(objtype);
            //            if (obj != null)
            //            {
            //                Inspector info = obj as Inspector;
            //                Alllist.Add(info);
            //            }
            //            break;
            //        }
            //        else
            //        {
            //            baseType = baseType.BaseType;
            //        }
            //    }
            //}
        }
        public override void OnFocus()
        {
            OnSelectionChange();
        }

        public override void OnLostFocus()
        {
            OnSelectionChange();
        }
        //选择其他对象
        public override void OnSelectionChange()
        {
            for (int k = 0; k < Alllist.Count; k++)
            {
                Alllist[k].SelectionChange();
            }
            Repaint();
        }
        private void Update()
        {
            for (int i = 0; i < Alllist.Count; i++)
            {
                Alllist[i].Updata();
            }
        }

        public virtual void OnInspectorUpdate()
        {
            for (int i = 0; i < Alllist.Count; i++)
            {
                Alllist[i].OnInspectorUpdate();
            }
            ///Debug.Log("当属性界面更新时");//几乎一直在更新
        }

        float mSlider;
        bool isShowPos = false;
        bool isTimeSlider = false;
        float mtimers = 100;
        private void OnGUI()
        {
            BeginWindows();
            for (int i = 0; i < Alllist.Count; i++)
            {
                Alllist[i].Draw();
            }
            EndWindows();
            StrX();
            {
                StrY();
                {
                    显示位置();
                    if (Button("收Scene"))
                    {
                        UtilEditor.收Scene();
                    }
                    if (Button("收Assets"))
                    {
                        UtilEditor.SetProjectBrowserFoldersCollapsed();
                    }
                    if (Button("收起组件"))
                    {
                        UtilEditor.收起组件();
                    }
                    if (Button("展开组件"))
                    {
                        UtilEditor.展开组件();
                    }
                    if (EditorApplication.isPlaying)
                    {
                        if (Camera.main)
                        {
                            mSlider = Camera.main.fieldOfView;
                            mSlider = GUILayout.HorizontalScrollbar(mSlider, 1, 1, 180);
                            Camera.main.fieldOfView = mSlider;
                        }
                        ComX(() =>
                        {
                            Toggle("", ref isTimeSlider);
                            if (isTimeSlider)
                            {
                                mtimers = GUILayout.HorizontalScrollbar(mtimers, 1, 1, 100);
                                Time.timeScale = mtimers * 0.01f;
                            }
                        }, GUILayout.MaxWidth(170));
                    }

                    if (GameView.isNull())
                    {
                        var ew = EditorWindow.focusedWindow;
                        //debug.log(ew.ToString());
                        if (ew)
                            if (ew.ToString() == " (UnityEditor.GameView)")
                            {
                                GameView = ew;
                            }
                    }
                    else if (Button("全屏"))
                    {
                        GameView.maximized = !GameView.maximized;
                    }
                }
                EndY();
                StrY();
                {
                    OnSubGUI();
                }
                EndY();
            }
            EndX();
        }
        EditorWindow GameView;
        public void 显示位置()
        {
            isShowPos = EditorGUILayout.Foldout(isShowPos, "显示位置:" + SelectionObj.Length.toString());
            if (isShowPos)
            {
                for (int i = 0; i < SelectionObj.Length; i++)
                {
                    GUILayout.BeginHorizontal();
                    SelectionObj[i] = EditorGUILayout.ObjectField(SelectionObj[i], typeof(GameObject), true, GUILayout.MaxWidth(70)) as GameObject;
                    EditorGUILayout.Vector3Field("", SelectionObj[i].transform.position);
                    if (SelectionObj[i].activeSelf)
                    {
                        if (Button("See"))
                        {
                            var _sceneView = SceneView.lastActiveSceneView;
                            if (_sceneView)
                            {
                                Vector3 pos = SelectionObj[i].transform.position;
                                pos.z = -20;
                                _sceneView.pivot = pos;
                            }
                        }
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        public virtual void OnSubGUI() { }
    }
    public class InspectorCom<T> : Inspector where T : UnityEngine.Object
    {
        public List<T> component = new List<T>();
        public override void SelectionChange()
        {
            base.SelectionChange();
            component.Clear();
            for (int i = 0; i < GetComponent.Count; i++)
            {
                component.Add(GetComponent[i] as T);
            }
        }
        public override Type GetInspectorType()
        {
            return typeof(T);
        }
    }
    public class Inspector : BaseEditorWindow
    {
        public List<Component> GetComponent = new List<Component>();

        public bool IsShow = false;
        public virtual void Updata() { }
        public virtual void OnInspectorUpdate() { }
        public Rect rect;
        public string Name;
        public SubsidiaryWindow MainWin;
        public int ID;
        public Inspector()
        {
            rect = new Rect(110, 220, 120, 200);
        }
        public virtual void Init(SubsidiaryWindow win, int windownID)
        {
            MainWin = win;
            ID = windownID;
            rect.x = rect.x * ID;
            Name = GetInspectorType().Name;
        }
        public virtual void SelectionChange()
        {
            GetComponent.Clear();
            var targets = Selection.gameObjects;
            if (targets.Length > 0)
            {
                for (int i = 0; i < targets.Length; i++)
                {
                    var ctf = targets[i].transform;
                    var conms = ctf.GetComponents(GetInspectorType());
                    for (int j = 0; j < conms.Length; j++)
                    {
                        GetComponent.Add(conms[j]);
                    }
                }
            }
            var cs = GetComponent.Count > 0;
            if (IsShow != cs)
            {
                IsShow = cs;
                if (IsShow)
                {
                    if (ID != 0)
                    {
                        RankingPos();
                    }
                }
            }
        }
        public void RankingPos()
        {
            Rect upRect = rect;
            for (int i = ID - 1; i >= 0; i--)
            {
                if (MainWin.Alllist[i].IsShow)
                {
                    upRect = MainWin.Alllist[i].rect;
                    break;
                }
            }
            rect.x = upRect.x + upRect.width + 10;
            rect.y = upRect.y;

            for (int i = ID + 1; i < MainWin.Alllist.Count; i++)
            {
                MainWin.Alllist[i].RankingPos();
            }
        }
        public virtual Type GetInspectorType() { return default(Type); }
        public void Draw()
        {
            if (!IsShow)
            {
                return;
            }

            //绘画窗口  
            rect = GUILayout.Window(ID, rect, DrawNodeWindow, Name);
        }
        Vector2 scrollPos;
        public void DrawNodeWindow(int id)
        {
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
            OnIGUI();
            EditorGUILayout.EndScrollView();

            //rect.height = scrollPos.y.toClamp(100,1000);

            //设置改窗口可以拖动  
            GUI.DragWindow();
        }
        public virtual void OnIGUI() { }

    }

}
namespace NodeBasedEditor
{
    public class NodeBasedEditor : EditorWindow
    {
        private List<Node> nodes;
        private List<Connection> connections;

        private GUIStyle nodeStyle;
        private GUIStyle selectedNodeStyle;
        private GUIStyle inPointStyle;
        private GUIStyle outPointStyle;

        private ConnectionPoint selectedInPoint;
        private ConnectionPoint selectedOutPoint;

        private Vector2 offset;
        private Vector2 drag;

        // [MenuItem("Window/Node Based Editor")]
        private static void OpenWindow()
        {
            NodeBasedEditor window = GetWindow<NodeBasedEditor>();
            window.titleContent = new GUIContent("Node Based Editor");
        }

        private void OnEnable()
        {
            nodeStyle = new GUIStyle();
            nodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node1.png") as Texture2D;
            nodeStyle.border = new RectOffset(12, 12, 12, 12);

            selectedNodeStyle = new GUIStyle();
            selectedNodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node1 on.png") as Texture2D;
            selectedNodeStyle.border = new RectOffset(12, 12, 12, 12);

            inPointStyle = new GUIStyle();
            inPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn left.png") as Texture2D;
            inPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn left on.png") as Texture2D;
            inPointStyle.border = new RectOffset(4, 4, 12, 12);

            outPointStyle = new GUIStyle();
            outPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn right.png") as Texture2D;
            outPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn right on.png") as Texture2D;
            outPointStyle.border = new RectOffset(4, 4, 12, 12);
        }

        private void OnGUI()
        {
            DrawGrid(20, 0.2f, Color.gray);
            DrawGrid(100, 0.4f, Color.gray);

            DrawNodes();
            DrawConnections();

            DrawConnectionLine(Event.current);

            ProcessNodeEvents(Event.current);
            ProcessEvents(Event.current);

            if (GUI.changed) Repaint();
        }

        private void DrawGrid(float gridSpacing, float gridOpacity, Color gridColor)
        {
            int widthDivs = Mathf.CeilToInt(position.width / gridSpacing);
            int heightDivs = Mathf.CeilToInt(position.height / gridSpacing);

            Handles.BeginGUI();
            Handles.color = new Color(gridColor.r, gridColor.g, gridColor.b, gridOpacity);

            offset += drag * 0.5f;
            Vector3 newOffset = new Vector3(offset.x % gridSpacing, offset.y % gridSpacing, 0);

            for (int i = 0; i < widthDivs; i++)
            {
                Handles.DrawLine(new Vector3(gridSpacing * i, -gridSpacing, 0) + newOffset, new Vector3(gridSpacing * i, position.height, 0f) + newOffset);
            }

            for (int j = 0; j < heightDivs; j++)
            {
                Handles.DrawLine(new Vector3(-gridSpacing, gridSpacing * j, 0) + newOffset, new Vector3(position.width, gridSpacing * j, 0f) + newOffset);
            }

            Handles.color = Color.white;
            Handles.EndGUI();
        }

        private void DrawNodes()
        {
            if (nodes != null)
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    nodes[i].Draw();
                }
            }
        }

        private void DrawConnections()
        {
            if (connections != null)
            {
                for (int i = 0; i < connections.Count; i++)
                {
                    connections[i].Draw();
                }
            }
        }

        private void ProcessEvents(Event e)
        {
            drag = Vector2.zero;

            switch (e.type)
            {
                case EventType.MouseDown:
                    if (e.button == 0)
                    {
                        ClearConnectionSelection();
                    }

                    if (e.button == 1)
                    {
                        ProcessContextMenu(e.mousePosition);
                    }
                    break;

                case EventType.MouseDrag:
                    if (e.button == 0)
                    {
                        OnDrag(e.delta);
                    }
                    break;
            }
        }

        private void ProcessNodeEvents(Event e)
        {
            if (nodes != null)
            {
                for (int i = nodes.Count - 1; i >= 0; i--)
                {
                    bool guiChanged = nodes[i].ProcessEvents(e);

                    if (guiChanged)
                    {
                        GUI.changed = true;
                    }
                }
            }
        }

        private void DrawConnectionLine(Event e)
        {
            if (selectedInPoint != null && selectedOutPoint == null)
            {
                Handles.DrawBezier(
                selectedInPoint.rect.center,
                e.mousePosition,
                selectedInPoint.rect.center + Vector2.left * 50f,
                e.mousePosition - Vector2.left * 50f,
                Color.white,
                null,
                2f
                );

                GUI.changed = true;
            }

            if (selectedOutPoint != null && selectedInPoint == null)
            {
                Handles.DrawBezier(
                selectedOutPoint.rect.center,
                e.mousePosition,
                selectedOutPoint.rect.center - Vector2.left * 50f,
                e.mousePosition + Vector2.left * 50f,
                Color.white,
                null,
                2f
                );

                GUI.changed = true;
            }
        }

        private void ProcessContextMenu(Vector2 mousePosition)
        {
            GenericMenu genericMenu = new GenericMenu();
            genericMenu.AddItem(new GUIContent("Add node"), false, () => OnClickAddNode(mousePosition));
            genericMenu.ShowAsContext();
        }

        private void OnDrag(Vector2 delta)
        {
            drag = delta;

            if (nodes != null)
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    nodes[i].Drag(delta);
                }
            }

            GUI.changed = true;
        }

        private void OnClickAddNode(Vector2 mousePosition)
        {
            if (nodes == null)
            {
                nodes = new List<Node>();
            }

            nodes.Add(new Node(mousePosition, 200, 50, nodeStyle, selectedNodeStyle, inPointStyle, outPointStyle, OnClickInPoint, OnClickOutPoint, OnClickRemoveNode));
        }

        private void OnClickInPoint(ConnectionPoint inPoint)
        {
            selectedInPoint = inPoint;

            if (selectedOutPoint != null)
            {
                if (selectedOutPoint.node != selectedInPoint.node)
                {
                    CreateConnection();
                    ClearConnectionSelection();
                }
                else
                {
                    ClearConnectionSelection();
                }
            }
        }

        private void OnClickOutPoint(ConnectionPoint outPoint)
        {
            selectedOutPoint = outPoint;

            if (selectedInPoint != null)
            {
                if (selectedOutPoint.node != selectedInPoint.node)
                {
                    CreateConnection();
                    ClearConnectionSelection();
                }
                else
                {
                    ClearConnectionSelection();
                }
            }
        }

        private void OnClickRemoveNode(Node node)
        {
            if (connections != null)
            {
                List<Connection> connectionsToRemove = new List<Connection>();

                for (int i = 0; i < connections.Count; i++)
                {
                    if (connections[i].inPoint == node.inPoint || connections[i].outPoint == node.outPoint)
                    {
                        connectionsToRemove.Add(connections[i]);
                    }
                }

                for (int i = 0; i < connectionsToRemove.Count; i++)
                {
                    connections.Remove(connectionsToRemove[i]);
                }

                connectionsToRemove = null;
            }

            nodes.Remove(node);
        }

        private void OnClickRemoveConnection(Connection connection)
        {
            connections.Remove(connection);
        }

        private void CreateConnection()
        {
            if (connections == null)
            {
                connections = new List<Connection>();
            }

            connections.Add(new Connection(selectedInPoint, selectedOutPoint, OnClickRemoveConnection));
        }

        private void ClearConnectionSelection()
        {
            selectedInPoint = null;
            selectedOutPoint = null;
        }
    }
    public class Node
    {
        public Rect rect;
        public string title;
        public bool isDragged;
        public bool isSelected;

        public ConnectionPoint inPoint;
        public ConnectionPoint outPoint;

        public GUIStyle style;
        public GUIStyle defaultNodeStyle;
        public GUIStyle selectedNodeStyle;

        public Action<Node> OnRemoveNode;

        public Node(Vector2 position, float width, float height, GUIStyle nodeStyle, GUIStyle selectedStyle, GUIStyle inPointStyle, GUIStyle outPointStyle, Action<ConnectionPoint> OnClickInPoint, Action<ConnectionPoint> OnClickOutPoint, Action<Node> OnClickRemoveNode)
        {
            rect = new Rect(position.x, position.y, width, height);
            style = nodeStyle;
            inPoint = new ConnectionPoint(this, ConnectionPointType.In, inPointStyle, OnClickInPoint);
            outPoint = new ConnectionPoint(this, ConnectionPointType.Out, outPointStyle, OnClickOutPoint);
            defaultNodeStyle = nodeStyle;
            selectedNodeStyle = selectedStyle;
            OnRemoveNode = OnClickRemoveNode;
        }

        public void Drag(Vector2 delta)
        {
            rect.position += delta;
        }

        public void Draw()
        {
            inPoint.Draw();
            outPoint.Draw();
            GUI.Box(rect, title, style);
        }

        public bool ProcessEvents(Event e)
        {
            switch (e.type)
            {
                case EventType.MouseDown:
                    if (e.button == 0)
                    {
                        if (rect.Contains(e.mousePosition))
                        {
                            isDragged = true;
                            GUI.changed = true;
                            isSelected = true;
                            style = selectedNodeStyle;
                        }
                        else
                        {
                            GUI.changed = true;
                            isSelected = false;
                            style = defaultNodeStyle;
                        }
                    }

                    if (e.button == 1 && isSelected && rect.Contains(e.mousePosition))
                    {
                        ProcessContextMenu();
                        e.Use();
                    }
                    break;

                case EventType.MouseUp:
                    isDragged = false;
                    break;

                case EventType.MouseDrag:
                    if (e.button == 0 && isDragged)
                    {
                        Drag(e.delta);
                        e.Use();
                        return true;
                    }
                    break;
            }

            return false;
        }

        private void ProcessContextMenu()
        {
            GenericMenu genericMenu = new GenericMenu();
            genericMenu.AddItem(new GUIContent("Remove node"), false, OnClickRemoveNode);
            genericMenu.ShowAsContext();
        }

        private void OnClickRemoveNode()
        {
            if (OnRemoveNode != null)
            {
                OnRemoveNode(this);
            }
        }
    }
    public class Connection
    {
        public ConnectionPoint inPoint;
        public ConnectionPoint outPoint;
        public Action<Connection> OnClickRemoveConnection;

        public Connection(ConnectionPoint inPoint, ConnectionPoint outPoint, Action<Connection> OnClickRemoveConnection)
        {
            this.inPoint = inPoint;
            this.outPoint = outPoint;
            this.OnClickRemoveConnection = OnClickRemoveConnection;
        }

        public void Draw()
        {
            Handles.DrawBezier(
            inPoint.rect.center,
            outPoint.rect.center,
            inPoint.rect.center + Vector2.left * 50f,
            outPoint.rect.center - Vector2.left * 50f,
            Color.white,
            null,
            2f
            );

            if (Handles.Button((inPoint.rect.center + outPoint.rect.center) * 0.5f, Quaternion.identity, 4, 8, Handles.RectangleCap))
            {
                if (OnClickRemoveConnection != null)
                {
                    OnClickRemoveConnection(this);
                }
            }
        }
    }
    public enum ConnectionPointType { In, Out }

    public class ConnectionPoint
    {
        public Rect rect;

        public ConnectionPointType type;

        public Node node;

        public GUIStyle style;

        public Action<ConnectionPoint> OnClickConnectionPoint;

        public ConnectionPoint(Node node, ConnectionPointType type, GUIStyle style, Action<ConnectionPoint> OnClickConnectionPoint)
        {
            this.node = node;
            this.type = type;
            this.style = style;
            this.OnClickConnectionPoint = OnClickConnectionPoint;
            rect = new Rect(0, 0, 10f, 20f);
        }

        public void Draw()
        {
            rect.y = node.rect.y + (node.rect.height * 0.5f) - rect.height * 0.5f;

            switch (type)
            {
                case ConnectionPointType.In:
                    rect.x = node.rect.x - rect.width + 8f;
                    break;

                case ConnectionPointType.Out:
                    rect.x = node.rect.x + node.rect.width - 8f;
                    break;
            }

            if (GUI.Button(rect, "", style))
            {
                if (OnClickConnectionPoint != null)
                {
                    OnClickConnectionPoint(this);
                }
            }
        }
    }

}